import { Node, Prefab, SpriteFrame } from "cc";
import Singleton from "../Base/Singleton";
import { IBullet, IClientInput, InputTypeEnum, IState } from "../Common";
import { IRoom } from "../Common/Api";
import { toFixed } from "../Common/Utils";
import { ActorManager } from "../Enity/Actor/ActorManager";
import { BulletManager } from "../Enity/Bullet/BulletManager";
import { EventEnum } from "../Enum";
import { JoyStickManager } from "../UI/JoyStickManager";
import { randomBySeed } from "../Utils";
import EventManager from "./EventManager";

const ACTOR_SPEED = 100;
const BULLET_SPEED = 600;

const MAP_WIDTH = 960;
const MAP_HEIGHT = 640;

const ACTOR_RADIUS = 50;
const BULLET_RADIUS = 10;

const BULLET_DAMAGE = 5;

export default class DataManager extends Singleton {
    static get Instance() {
        return super.GetInstance<DataManager>();
    }

    myPlayerId: number = 1;
    frameId: number = 1;
    lastState: IState = null;
    state: IState = null;
    roomInfo: IRoom
    jm: JoyStickManager;
    stage: Node;
    actorMap: Map<number, ActorManager> = new Map();
    bulletMap: Map<number, BulletManager> = new Map();
    prefabs: Map<string, Prefab> = new Map();
    textureMap: Map<string, SpriteFrame[]> = new Map();

    applyInput(input: IClientInput) {
        switch (input.type) {
            case InputTypeEnum.ActorMove: {
                const {
                    id,
                    dt,
                    direction: { x, y }
                } = input;

                const actor = this.state.actors.find(e => e.id === id);
                actor.direction.x = x;
                actor.direction.y = y;

                actor.position.x += toFixed(x * dt * ACTOR_SPEED);
                actor.position.y += toFixed(y * dt * ACTOR_SPEED);
            }
                break;
            case InputTypeEnum.WeaponShoot: {
                console.log("WeaponShoot  ", input)
                const { owner, position, direction } = input;
                const bullet: IBullet = {
                    id: this.state.nextBulletId++,
                    owner,
                    type: this.actorMap.get(owner).bulletType,
                    position: {
                        x: position.x,
                        y: position.y,
                    },
                    direction: {
                        x: direction.x,
                        y: direction.y,
                    },
                }

                EventManager.Instance.emit(EventEnum.BulletBorn, bullet.owner);
                this.state.bullets.push(bullet);
            }
                break;
            case InputTypeEnum.TimePast: {
                const { dt } = input;
                const { bullets, actors } = this.state;

                for (let i = bullets.length - 1; i >= 0; i--) {
                    const bullet = bullets[i];
                    let isHit = false;
                    for (let j = actors.length - 1; j >= 0; j--) {
                        const actor = actors[j];
                        if ((actor.position.x - bullet.position.x) ** 2 + (actor.position.y - bullet.position.y) ** 2
                            <= (ACTOR_RADIUS + BULLET_RADIUS) ** 2) {
                            const random = randomBySeed(this.state.seed);
                            this.state.seed = random;
                            const damage = (random / 233280 >= 0.5) ? BULLET_DAMAGE * 2 : BULLET_DAMAGE;
                            console.log("damage  ", damage)
                            actor.hp -= damage;
                            EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id,
                                {
                                    x: toFixed((actor.position.x + bullet.position.x) / 2),
                                    y: toFixed((actor.position.y + bullet.position.y) / 2)
                                }
                            )
                            bullets.splice(i, 1);
                            isHit = true;
                            break;
                        }
                    }

                    if (!isHit && (Math.abs(bullet.position.x) > MAP_WIDTH / 2
                        || Math.abs(bullet.position.y) > MAP_HEIGHT / 2)) {
                        EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id,
                            {
                                x: bullet.position.x,
                                y: bullet.position.y
                            }
                        )
                        bullets.splice(i, 1);
                    }
                }
                for (const bullet of bullets) {
                    bullet.position.x += toFixed(bullet.direction.x * dt * BULLET_SPEED);
                    bullet.position.y += toFixed(bullet.direction.y * dt * BULLET_SPEED);
                }
            }
                break
            default:
                break;
        }
    }
}
